local skynet = require "skynet"
local Object = require("core").Object
local Seat = require("Seat")
local CMD = require "main_proto"
local CMDGAME = require "game_proto"
local bufferrw = require "buffrw"
local Sraw = require "stable.raw"
local lobbysql = require "lobbysql"
local CEN = require "center_proto"
local Prop = require "Propinfo"
local filter = require("wordfilter")

Sraw.init()
local MaxPlayerCount = 8

local buffwrite = bufferrw.BuffWrite
local buffread  = bufferrw.BuffRead

local manager       = skynet.localname(".manager")
local center_conn   = skynet.localname(".center_con")

local TABLESTATUS_END  =       0       --桌子销毁
local TABLESTATUS_START =      1       --游戏开始
local TABLESTATUS_READY_IN =   2       --游戏未开始，进入
local TABLESTATUS_READY_OUT =  3       --游戏未开始，退出


local AGENT_TBL_START=         1
local AGENT_TBL_END   =        2
local AGENT_TBL_DISMISS=       3
local AGENT_TBL_DISMISSINREADY =4


--用于亲友群房间的结束处理
local GAMEEND_COMPLETE=1
local GAMEEND_DISS=0

local function SendToCenter(mscmd, scmd, msg)
    skynet.send(center_conn,"lua","sendToCenter",mscmd, scmd, msg)
end


local Room = {}

Room.GAME_STATUS_WAIT = 0       --游戏未开始
Room.GAME_STATUS_BEGIN = 1      --游戏开始
Room.GAME_STATUS_WAITNEXT = 2   --等待下一局开始

Room.externData 	= nil
Room.m_szRoomInfo 	= nil

Room.m_nGameId = skynet.getenv('game_id')
--Room.m_nPlatFormId = tonumber(skynet.getenv('platform_type')) or 1
Room.m_nRoomType = tonumber(skynet.getenv('room_type') or 1)

Room.m_nRoomId = 0
Room.m_pChairs = {}
Room.m_dwOwnerPlayerId = nil
Room.m_wTotalJu = nil
Room.m_wCurJu = 1
Room.m_wZhiFuRen = nil
Room.m_startTime = nil
Room.m_nGameState = 0
Room.m_nMa = nil   
Room.m_nFangPaoOrZiMo = nil
Room.m_nDianPaoMaOrZiMoMa = nil  
Room.m_nPlayerCount = nil 
Room.m_nDiFen = nil
Room.m_nNeedFangKa = nil
Room.m_nBanker = nil
Room.m_tCreateTime = nil   --桌子创建时间
Room.m_bIsStarted = 0
--解散相关
Room.m_nJieSanApplyerChairId = nil --申请解散用户椅子id
Room.m_nJieSanTimePoint = nil --申请解散
Room.m_nDismissId = 0
--代理相关
Room.m_nAgentID = 0
Room.m_nMode = nil
--定时器相关
Room.m_nTimerWorkCount = nil   --10分钟定时器，没操作解散桌子
Room.m_n1MinCheckTick = 0      --人都坐满了但还有人没有准备踢人

Room.m_nGroupId = 0
Room.m_bGoupPayFlag = false     --亲友群是否已支付

Room.CheckReady = false --游戏结束后把十分钟内不准备的踢掉

local gameLogic

local function Send_Data(addr,cmd,msg)
    if math.floor(addr) > 0 then
        skynet.send(math.floor(addr),"lua",cmd,msg)
    end
end

local function IsGold()
    return Room.m_nRoomType == 2
end

--创建游戏逻辑
function Room.CreateGameLogic(room)
	local CGameLogic = require("tableframe")
	local gameLogic = nil
	if CGameLogic then
		gameLogic = CGameLogic:new(Room)
	end
	return gameLogic
end
--[[加载金币场配制
function Manager.LoadGoldInfo()
     Manager.m_nDiFen = tonumber(skynet.getenv('nDiFen') or 1)
     Manager.m_nMa = tonumber(skynet.getenv('nMa') or 0)
     Manager.m_nFangPaoOrZiMo = tonumber(skynet.getenv('nFangPaoOrZiMo') or 0)
     Manager.m_nDianPaoMaOrZiMoMa = tonumber(skynet.getenv('nDianPaoMaOrZiMoMa') or 0) 
     Manager.m_nKeQiangGang = tonumber(skynet.getenv('nKeQiangGang') or 0)
     Manager.
end
]]
--创建房间后初始化房间
function Room.Init(roomId)
	Room.m_nRoomId = math.floor(roomId)
	Room.m_dwOwnerPlayerId = 0
    Room.m_nPlayerCount    = 0
	Room.m_wTotalJu        = 0
	Room.m_wCurJu          = 1
	Room.m_nMa             = tonumber(skynet.getenv('nMa') or 0)
	Room.m_nDiFen 	       = tonumber(skynet.getenv('nDiFen') or 1)
	Room.m_wZhiFuRen  	   = 0
	Room.m_nGameState      = Room.GAME_STATUS_WAIT
    Room.m_nFangPaoOrZiMo  = tonumber(skynet.getenv('nFangPaoOrZiMo') or 0)
    Room.m_nDianPaoMaOrZiMoMa = tonumber(skynet.getenv('nDianPaoMaOrZiMoMa') or 0)
    Room.m_nKeQiangGang    = tonumber(skynet.getenv('nKeQiangGang') or 0)
	Room.externData        = 0
    Room.m_nNeedFangKa     = 0
    Room.m_nMinEnterJinBi  = tonumber(skynet.getenv('nMinEnterJinBi') or 1)
    Room.m_tCreateTime     = skynet.time()
    Room.m_nMaxEnterJinBi  = tonumber(skynet.getenv('nMaxEnterJinBi') or 0)
    skynet.error("Room.Init tableID=", Room.m_nRoomId)
    Room.m_nTimerWorkCount = 0

    --skynet.timeout(100, function() Room:OnTimerCheckWork(table_id) end)
	gameLogic = Room.CreateGameLogic()
    Room.m_szRoomInfo = gameLogic:SetTableData(Room.m_nRoomType,Room.m_nPlayerCount,Room.m_nDiFen,Room.m_nMa,Room.m_nFangPaoOrZiMo,Room.m_nDianPaoMaOrZiMoMa,Room.m_nKeQiangGang,0)
    if gameLogic then
		local nPlayerCount,seatIds = gameLogic:GetSeatCount()
        Room.m_nPlayerCount = nPlayerCount
		for i=0,Room.m_nPlayerCount-1 do
			Room.m_pChairs[i] = Seat:new(i)
		end

        for _,seatId in pairs(seatIds) do
            Room.m_pChairs[seatId-1].m_isValid = 1
        end
		gameLogic:InitGameData()
	end

    local file = io.open("dict.txt", "r")
    if file then
        while true do
            local ourline = file:read()
            if not ourline then
                break
            end
            filter:addWord(ourline)
        end
    end

	--skynet.fork(Room.RoomExpire)
end
--初始化代理数据
function Room.InitAgentInfo(nMode)
    if 0 == Room.nAgentID then
        return
    end
    Room.m_nMode = nMode

    skynet.error("Room.m_nMode = ",Room.m_nMode)
    --初始化成功就写入数据库
    local ar = {}
    ar.nPlayerID    = Room.m_nAgentID
    ar.nTableID     = Room.m_nRoomId
    ar.nMode        = Room.m_nMode
    ar.nGameID      = Room.m_nGameId
    ar.nPlayerCount = Room.m_nPlayerCount
    ar.nRound       = Room.m_wTotalJu
    ar.nCost        = Room.m_nNeedFangKa
    ar.szRoomInfo   = Room.m_szRoomInfo
    local pResp = lobbysql.AddAgentRoom(ar)
    local msg = string.pack("<I4I4i4",pResp.nPlayerID,pResp.nTableID,pResp.nResult)
    SendToCenter(CMD.Main_Hall_CMD,CMD.Sub_CreateAgentTableResp2,msg)
end

--房间过期定时器
function Room.RoomExpire(room) -- 10分钟定时器
    skynet.sleep(6000*10)
    Room.SendMsgToAll(Room.PackCenterHintMsg("房间十分钟未开始游戏，房间解散"))
    if Room.m_bIsStarted ~= 0 then 
        return 
    else
        skynet.error("[manager] OnTimer10MinReadyCheck",table_id)
        Room.Dismiss()
    end
end

--玩家加入
function Room.Join(Player)
    local sitSeat = nil
    for i = 0, Room.m_nPlayerCount-1 do
        local seat = Room.m_pChairs[i]
        if seat.m_isValid == 1 and not seat.Player then
            skynet.error("seat.m_wChairId=",seat.m_wChairId)
            seat:Sit(Player) 
            sitSeat = seat
            break 
        end

    end
    
    if sitSeat then -- 坐成功
        local BuffWrite = buffwrite.new()
        Player.nScore = 0
        Player.nRoomAddr = skynet.self()
        Player.nRoomId = Room.m_nRoomId
        BuffWrite:clean()  
        BuffWrite:proto(301, 2002)
        BuffWrite:int4(Room.m_nRoomId)
        --BuffWrite:int2(seatId)
        BuffWrite:int2(sitSeat.m_wChairId)
        BuffWrite:int2(Room.m_wTotalJu)
        BuffWrite:int2(Room.m_wCurJu)
        BuffWrite:int4(Room.m_nMa)
        BuffWrite:int4(Room.m_nFangPaoOrZiMo)
        BuffWrite:int4(Room.m_nDianPaoMaOrZiMoMa)
        BuffWrite:int4(Room.m_nDiFen)
        Room.SendMsgToUser(sitSeat,BuffWrite.buff)

        Room.SendRoomInfo(sitSeat)

        Room.SendAllPlayerInfoToMe(sitSeat)
        Room.SendMyPlayerInfoToOther(sitSeat)

        gameLogic:OnSitDownSucess(sitSeat)

        if Room.GetPlayerCount() == 1 then -- 第一个人进的时候要通知创建房间
            local msg = string.pack("I4I4I4",Room.m_nRoomId,Player.nPlayerId,0)
            SendToCenter(CEN.Main_Center_module,CEN.Sub_ModuleToCenter_CreateTable,msg)
        end

        Room.NotifyCenterServerTableStatus(TABLESTATUS_READY_IN,math.floor(Player.nPlayerId))

        if Room.GetPlayerCount() == Room.m_nPlayerCount then  --人坐满了要把房间从空闲房间中删除掉
            skynet.send(manager,"lua","TableNotIdle",Room.m_nRoomId)
        end

        Room.CheckSameIP()
         --发送一个欺骗消息
        Room.OnNetMsgReadyActionReq(string.pack("I2I2I4",0,0,0),Player)
    end
end
--SendAllPlayerInfoToMe
function Room.SendAllPlayerInfoToMe(seat)
    skynet.error("[itableframe] SendAllPlayerInfoToMe")
    local BuffWrite = buffwrite.new()
    local playmsg = {}
    local count = 0
    local BuffWrite = buffwrite.new()
    for _,seat in pairs(Room.m_pChairs) do
        if  seat.Player then
            BuffWrite:clean()           
            BuffWrite:int4(seat.Player.nPlayerId)
            BuffWrite:int2(seat.m_wChairId)
            BuffWrite:int4(seat.Player.nSex)
            BuffWrite:int4(seat.Player.nScore)
            BuffWrite:int8(seat.Player.llJinBi)
            BuffWrite:int4(seat.Player.nDiamond)
            BuffWrite:int1(0)
            BuffWrite:int1(seat.IsOffLine and 1 or 0)
            BuffWrite:str(seat.Player.szName, 64)
            BuffWrite:str(seat.Player.szHeadUrl, 192)
            BuffWrite:str(seat.Player.szIp, 32)
            BuffWrite:str(seat.Player.szSign, 128)
            BuffWrite:int1(seat.IsReady)
            BuffWrite:float(seat.GPS_X)
            BuffWrite:float(seat.GPS_Y)
            BuffWrite:int4(seat.Player.nExternCode)
            count = count + 1
            table.insert(playmsg, BuffWrite.buff)
        end
    end

    BuffWrite:clean()  
    BuffWrite:proto(303, 2001)
    BuffWrite:int2(count)
    local msg = BuffWrite.buff..table.concat(playmsg)
    Room.SendMsgToUser(seat,msg)
end

function Room.SendMyPlayerInfoToOther(seat)
    if not seat and not seat.Player then return end
    local BuffWrite = buffwrite.new()
    BuffWrite:clean()
    BuffWrite:proto(303, 2002)                      --SendMyPlayerInfoToOther
    BuffWrite:int2(1)           
    BuffWrite:int4(seat.Player.nPlayerId) 
    BuffWrite:int2(seat.m_wChairId)
    BuffWrite:int4(seat.Player.nSex)
    BuffWrite:int4(seat.Player.nScore)
    BuffWrite:int8(seat.Player.llJinBi)
    BuffWrite:int4(seat.Player.nDiamond)
    BuffWrite:int1(0)
    BuffWrite:int1(seat.IsOffLine and 1 or 0)
    BuffWrite:str(seat.Player.szName, 64)
    BuffWrite:str(seat.Player.szHeadUrl, 192)
    BuffWrite:str(seat.Player.szIp, 32)
    BuffWrite:str(seat.Player.szSign, 128)
    BuffWrite:int1(seat.IsReady)
    BuffWrite:float(seat.GPS_X)
    BuffWrite:float(seat.GPS_Y)
    BuffWrite:int4(seat.Player.nExternCode)
    Room.SendMsgToAll(BuffWrite.buff,seat.m_wChairId)
end

function Room.GetPlayerCount()
    local playcount = 0
    for _,seat in pairs(Room.m_pChairs) do
        if seat.Player then
            playcount = playcount + 1
        end
    end
    return playcount
end

--检查是否开始游戏
function Room.CheckStartGame()

    local playcount,readycount = 0,0
    for _,seat in pairs(Room.m_pChairs) do
        if seat.Player then
          playcount = playcount + 1
        end

        if seat.IsReady == 1 then
            readycount = readycount+1
        end
    end

    skynet.error("Room.CheckStartGame playCount",playcount,"readycount=",readycount,Room.m_nPlayerCount)
    if playcount == Room.m_nPlayerCount then
        if readycount >= playcount then
            Room.GameStart()
        end
    end
end
--[[人齐一分钟内没有开始游戏清除没有准备的玩家
function Room.ClearNotReadyPlayer()
    Room.m_n1MinCheckTick = skynet.time()
    local time = Room.m_n1MinCheckTick
    local msg = string.pack(">I2>I2<i",CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_1MIN_CLOSE,60)
    Room.SendMsgToAll(msg)
    skynet.sleep(6000)
    if time == Room.m_n1MinCheckTick then
        if Room.m_wZhiFuRen==1 then
            for _,seat in pairs(Room.m_pChairs) do
                if math.floor(seat.Player.nPlayerId) == math.floor(Room.m_dwOwnerPlayerId) then
                    if seat.IsReady == 1 then --房主准备了
                        break
                    end
                    Room.SendMsgToAll(Room.PackCenterHintMsg("由于房主长时间未准备，房间已被解散！"))
                    Room.OnNetMsgStandUpReq(seat.Player)
                    return
                end 
            end
        end
        for _,seat in pairs(Room.m_pChairs) do
            if seat.Player and seat.IsReady==0 then
                Room.SendMsgToUser(seat,Room.PackCenterHintMsg("由于您在1分钟内未举手准备，现把您返回大厅"))
                Room.OnNetMsgStandUpReq(seat.Player)
            end
        end
    end
end
]]
function Room.CheckSameIP()
    local szIp = {}
    for chair_id, chair_obj in pairs(Room.m_pChairs) do 
        if chair_obj.Player  then
           table.insert(szIp,chair_obj.Player.szIp)
        end
    end
    if #szIp < 2 then 
        return 
    end
    table.sort(szIp)
    for i =1 , #szIp do 
        if szIp[i] == szIp[i+1] then 
            local BuffWrite = buffwrite.new()
            BuffWrite:proto(CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg) --300 2008
            BuffWrite:str("请注意：本房间有玩家IP地址相同",96)
            Room.SendMsgToAll(BuffWrite.buff)
            break 
        end
    end
end


--预进入
function Room.PreJoin(Player)
    local is_enter = 0
    for _,seat in pairs(Room.m_pChairs) do
        if seat.m_isValid == 1 and not seat.Player then 
            is_enter = 1
            break
        end
    end

    if is_enter==0 then
        Send_Data(Player.nAgentAddr,"send_data",Room.PackCenterHintMsg("房间已满"))
    end

    if is_enter==1 and Room.m_wZhiFuRen ~= 1 then
       if Player.nDiamond < Room.m_nNeedFangKa then
            is_enter = 0
            Send_Data(Player.nAgentAddr,"send_data",Room.PackCenterHintMsg("您的钻石不够!"))
       end
    end

    skynet.error("is_enter =",is_enter," Room.m_nAgentID =",Room.m_nAgentID," Room.m_nMode=",Room.m_nMode)

    if is_enter==1 and Room.m_nAgentID ~= 0 and Room.m_nMode == 1 then
        local req = {nPlayerID = math.floor(Player.nPlayerId),nAgentID = math.floor(Room.m_nAgentID)}
        if not lobbysql.CheckPlayerInAgentTable(req) then
            is_enter = 0
            Send_Data(Player.nAgentAddr,"send_data",Room.PackCenterHintMsg("您的邀请码不对!"))
        end
    end

    local msg = string.pack(">I2>I2<I1",CMD.Main_ClientAndGameSvr_LobbyModle, CMD.Sub_GameSvrToClient_LobbyModle_PreEnterResult,is_enter)
    Send_Data(Player.nAgentAddr,"send_data",msg)
end

--发送房间信息
function Room.SendRoomInfo(seat)
	local BuffWrite = buffwrite.new()
    BuffWrite:proto(301, 2014)
    BuffWrite:int1(0)
    BuffWrite:int4(Room.m_dwOwnerPlayerId)
    BuffWrite:int1(Room.m_wZhiFuRen)
    BuffWrite:str(Room.m_szRoomInfo, 128)
    BuffWrite:int4(Room.m_nGameId)
    Room.SendMsgToUser(seat,BuffWrite.buff)
--[[
    if Room.m_nGameState ~= Room.GAME_STATUS_WAIT then 
        return 
    end

    BuffWrite:clean()
    BuffWrite:proto(CMDGAME.Main_ClientAndGameSvr_TableModle, CMDGAME.Sub_GameSvrToClient_TableModle_10MIN_CLOSE) --303 2063
    BuffWrite:int4(math.ceil(Room.m_tCreateTime + 600 - skynet.time())) -- 测试为120s 
    Room.SendMsgToUser(seat,BuffWrite.buff)
]]
end

--断线重连（玩家重新进入）
function Room.ReJoin(Player)
    local seat = Room.GetSeatByPlayer(Player)
    skynet.error("[manager] OnPlayerOfflineBack ",Player.nPlayerId,Room.m_nRoomId)
    skynet.error("gameLogic.currentUser=", gameLogic.currentUser)
    if seat then
        Room.SendRoomInfo(seat)
        Room.SendMeOfflineBackSucc(seat)
        Room.SendAllPlayerInfoToMe(seat)
        gameLogic:UserComeBack(seat)

        if Room.m_nGameState ~= 0 then
            if gameLogic:IsPlaying() then
                local BuffWrite = buffwrite.new()
                BuffWrite:proto(CMDGAME.Main_ClientAndGameSvr_TableModle, CMDGAME.Sub_GameSvrToClient_TableModle_GameStart)
                Send_Data(Player.nAgentAddr,"send_data", BuffWrite.buff)
                gameLogic:OnPlayerOfflineBack(seat)
            else
                Room.OnNetMsgUserGoOnGameReq(Player)
            end
        end    

        if Room.m_nJieSanApplyerChairId ~= nil then
            Room.SendJieSanData(seat)
        end
    end
end

function Room.SendMeOfflineBackSucc(seat)
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(301,2003)
    BuffWrite:int4(Room.m_nRoomId)
    BuffWrite:int2(seat.m_wChairId)
    BuffWrite:int2(Room.m_wTotalJu)
    BuffWrite:int2(Room.m_wCurJu)
    BuffWrite:int4(Room.m_nMa)
    BuffWrite:int4(Room.m_nFangPaoOrZiMo)
    BuffWrite:int4(Room.m_nDianPaoMaOrZiMoMa)
    BuffWrite:int2(Room.m_bIsStarted) 
    BuffWrite:Int4(seat.Player.nDiamond)    
    BuffWrite:int4(seat.Player.nScore)
    BuffWrite:int4(Room.m_nDiFen)
    BuffWrite:int4(Room.m_nPlayerCount)
    Room.SendMsgToUser(seat,BuffWrite.buff)
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(301,2036)
    BuffWrite:int2(seat.m_wChairId)
    BuffWrite:int1(1)
    Room.SendMsgToAll(BuffWrite.buff)

    Room.UpdatePlayerOnLineInfo(seat,0)
end
--玩家点击准备
function Room.OnNetMsgReadyActionReq(smsg, Player)
	if Room.m_nGameState ~= Room.GAME_STATUS_WAIT  and Room.m_nGameState ~= Room.GAME_STATUS_WAITNEXT then
		return
	end
    local nready = string.unpack("I4", smsg, 5)

	local seat = Room.GetSeatByPlayer(Player)

    if nready == 0 then 
        seat.IsReady = 1
    else
        seat.IsReady = 0
    end

    local msg = string.pack(">I2>I2<I4I2",CMDGAME.Main_ClientAndGameSvr_TableModle, CMDGAME.Sub_GameSvrToClient_TableModle_ReadyActionResp, nready, seat.m_wChairId)
    --Room.SendMsgToUser(seat,msg)    
    Room.SendMsgToAll(msg)

    Room.CheckStartGame()
end

--玩家点击继续
function Room.OnNetMsgUserGoOnGameReq(player)

    skynet.error("Room.m_nGameState = ",Room.m_nGameState)

	if Room.m_nGameState ~= Room.GAME_STATUS_WAITNEXT and Room.m_nGameState ~= Room.GAME_STATUS_WAIT then
		return
	end

	local seat = Room.GetSeatByPlayer(player)
	if seat.IsReady == Seat.SEAT_STATUS_READY then
		return
	end
    seat.IsReady = Seat.SEAT_STATUS_READY
    --需要发送准备消息给客户端
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(CMDGAME.Main_ClientAndGameSvr_TableModle, CMDGAME.Sub_GameSvrToClient_TableModle_TableUserReady)
    BuffWrite:int2(seat.m_wChairId)  
    Room.SendMsgToAll(BuffWrite.buff) 

    Room.CheckStartGame()
end

--游戏开始
function Room.GameStart()
	if Room.m_nGameState ~= Room.GAME_STATUS_WAIT and Room.m_nGameState ~= Room.GAME_STATUS_WAITNEXT then
		return
	end
--[[
    if Room.m_bIsStarted == 0 then
        --skynet.fork(Room.OnTimerCheckWork)
        Room.m_bIsStarted = 1
        Room.m_n1MinCheckTick = 0
    end
]]
    Room.CheckReady = false
    Room.m_startTime = tostring(os.date("%Y-%m-%d %H:%M:%S",os.time()))
	--房间局数自增
	Room.m_nGameState = Room.GAME_STATUS_BEGIN
	for _,seat in pairs(Room.m_pChairs) do
		if seat.Player then
			seat.status = Seat.SEAT_STATUS_START
			seat.playCount = seat.playCount + 1
		end
        seat.nScoreJu = 0
	end

    for _,seat in pairs(Room.m_pChairs) do
        local nJinBiToSub = -1*Room.m_nDiFen;
        if seat.Player then
            lobbysql.AddOrSubPlayerJinBi(seat.Player,nJinBiToSub,"底分扣除")
            Room.UpdatePlayerBasicInfo(seat.Player)
        end
    end

    Room.UpdateAllPlayerJinBiToClient()

	gameLogic:OnEventGameStart()
    gameLogic:StartOneMinTimer()

    Room.NotifyCenterServerTableStatus(TABLESTATUS_START)
    Room.AgentGameChg(AGENT_TBL_START)
end

--小局游戏结束
function Room.ConcludeGame(...)
    gameLogic:StopOneMinTimer()
	Room.m_nGameState = Room.GAME_STATUS_WAITNEXT

    for _,seat in pairs(Room.m_pChairs) do
        seat.IsReady = Seat.SEAT_STATUS_WAIT
    end

	local ret = gameLogic:ConcludeGame(...)

    for _,seat in pairs(Room.m_pChairs) do
        skynet.error("Room.seat.nScoreJu=",seat.nScoreJu)
        if seat.nScoreJu ~= 0 and seat.Player then
            lobbysql.AddOrSubPlayerJinBi(seat.Player,seat.nScoreJu,"游戏输赢")
        end
    end
    Room.UpdateAllPlayerJinBiToClient()

    Room.ResetGame()
    --金币场要清除断线和金币不够的玩家
    Room.ClearUsers()
end

function Room.ClearUsers()
    for _,seat in pairs(Room.m_pChairs) do
        local standup = false
        --清除断线玩家
        if seat.Player and seat.IsOffLine then
            standup = true
        end
        --清除没钱的
        if seat.Player and seat.Player.llJinBi < Room.m_nMinEnterJinBi then
            standup = true
            Room.SendMsgToUser(seat,Room.PackCenterHintMsg("您的金币少于 "..Room.m_nMinEnterJinBi))
        end

        if standup then
            Room.OnNetMsgStandUpReq(seat.Player)
        end
    end
end

--游戏结束
function Room.ConcludeGameFriend()
    --Room.WriteZhanJiDbEx()
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(303, 2028)
    BuffWrite:int4(Room.m_nPlayerCount)
    for i=0 , Room.m_nPlayerCount-1 do
        local chair_obj = Room.m_pChairs[i]
        if chair_obj.Player then
            BuffWrite:int4(chair_obj.Player.nScore)
        end
    end
    Room.SendMsgToAll(BuffWrite.buff)   
end
--每小局写战绩
function Room.WriteZhanJiDbEx()
    skynet.error("写每局小战绩")
    local zhji = {
    nGameId = tonumber(Room.m_nGameId),
    nTableId = Room.m_nRoomId,
    nPlayerId = nil,
    szNickName = nil,

    szStarTime = Room.m_startTime,
    szEndTime = tostring(os.date("%Y-%m-%d %H:%M:%S",os.time())),
    szRecToken = "123456",
    nDiFen = Room.m_nDiFen,
    jushu = Room.m_wCurJu,
    nTotalJu = Room.m_wTotalJu,

    fuju = nil,
    fuType = nil,
    fuFangShi = nil,
    zhangjia = Room.m_nBanker or -1,

    nPlayerIdArr = {},
    nArrowArr = {},
    nScores = {},
    szNames = {},

    mingGanArr = {},
    anganArr = {},

    wMyChairId = nil,
    bEndJu = Room.m_wCurJu >= Room.m_wTotalJu and 1 or 0,
    }

    local bankerSeat = Room.m_pChairs[Room.m_nBanker]
    
    if bankerSeat and bankerSeat.Player then
        table.insert(zhji.nPlayerIdArr,math.floor(bankerSeat.Player.nPlayerId))
        table.insert(zhji.nArrowArr,math.floor(bankerSeat.m_wChairId))
        table.insert(zhji.nScores,math.floor(bankerSeat.nScoreJu or 0))
        table.insert(zhji.szNames,bankerSeat.Player.szName or "")
        table.insert(zhji.mingGanArr,math.floor(bankerSeat.nMingGang or 0))
        table.insert(zhji.anganArr,math.floor(bankerSeat.nAnGang or 0))
    end

    for i=0,Room.m_nPlayerCount-1 do
        local seat = Room.m_pChairs[i]
        if seat.Player and seat.m_wChairId ~= Room.m_nBanker then
            table.insert(zhji.nPlayerIdArr,math.floor(seat.Player.nPlayerId))
            table.insert(zhji.nArrowArr,math.floor(seat.m_wChairId))
            table.insert(zhji.nScores,math.floor(seat.nScoreJu or 0))
            table.insert(zhji.szNames,seat.Player.szName or "")
            table.insert(zhji.mingGanArr,math.floor(seat.nMingGang or 0))
            table.insert(zhji.anganArr,math.floor(seat.nAnGang or 0))
        end
    end

    for i=0,Room.m_nPlayerCount-1 do
        local seat = Room.m_pChairs[i]
        if seat.Player then
            zhji.wMyChairId = seat.m_wChairId
            zhji.fuju       = seat.fuju or 0
            zhji.fuType     = seat.fuType or 0
            zhji.fuFangShi  = seat.fuFangShi  or 0         
            zhji.nPlayerId  = math.floor(seat.Player.nPlayerId)
            zhji.szNickName = seat.Player.szName or ""
            lobbysql.WriteUserZhanJi(zhji)
        end
    end
end

function Room.ResetGame() 
    for _, seat in pairs(Room.m_pChairs) do 
        if seat.Player then 
            seat.IsReady = 0  
        end
    end
    --Room.m_wCurJu = Room.m_wCurJu + 1 

    --流局时ResetGame，要使Room状态等待，否则无法游戏开始   zr_add
    Room.m_nGameState = Room.GAME_STATUS_WAITNEXT

    skynet.fork(Room.ClearNotReadyPlayer)
end

function Room.ClearNotReadyPlayer()
    Room.CheckReady = true
    local time = 0
    while Room.CheckReady do
        skynet.sleep(100)
        time = time+1
        if time >= 10*60 then
            for _,seat in pairs(Room.m_pChairs) do
                if seat.Player and seat.IsReady == 0 then
                    Room.OnNetMsgStandUpReq(seat.Player)
                end
            end
            return
        end
    end
end

function Room.ConcluedGamePayFangka()
    if Room.m_nGroupId > 0 then return end

    if Room.m_wCurJu == 1 or Room.m_wCurJu == Room.m_wTotalJu/2 then
        local nNeedFangKa = 0
        if Room.m_wCurJu == 1 then 
            if Room.m_nAgentID ~= 0 then
                Room.AgentGameChg(AGENT_TBL_END)
            end
            nNeedFangKa = Room.m_nNeedFangKa/2
        elseif Room.m_wCurJu == Room.m_wTotalJu/2 then 
            nNeedFangKa = Room.m_nNeedFangKa/2
        end

        for _ ,seat in pairs(Room.m_pChairs) do 
            if seat.Player then                
                if Room.m_wZhiFuRen == 1 then 
                    if Room.m_dwOwnerPlayerId == seat.Player.nPlayerId then
                        skynet.call(skynet.localname(".sql"),"lua","OnSubPlayerCardCount",seat.Player.nPlayerId,nNeedFangKa)
                        seat.Player.nDiamond = seat.Player.nDiamond - nNeedFangKa
                        Room.UpdatePlayerBasicInfo(seat.Player)
                        break
                    end
                else
                    if seat.Player.nDiamond >= nNeedFangKa then 
                        skynet.call(skynet.localname(".sql"),"lua","OnSubPlayerCardCount",seat.Player.nPlayerId,nNeedFangKa)
                        seat.Player.nDiamond = seat.Player.nDiamond - nNeedFangKa
                        Room.UpdatePlayerBasicInfo(seat.Player)
                    end
                end
            end
        end
    end
end

function Room.UpdatePlayerBasicInfo(Player)
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(300, 2007)
    BuffWrite:Int4(Player.nPlayerId)
    BuffWrite:Int4(Player.nDiamond)
    BuffWrite:int4(Player.nScore)
    BuffWrite:int8(Player.llJinBi)
    BuffWrite:int4(Player.nExternCode)
    Send_Data(Player.nAgentAddr, "send_data", BuffWrite.buff)
end

function Room.Close()
    Room.NotifyCenterServerTableStatus(TABLESTATUS_END)
end

function Room.Dismiss()
	for _,seat in pairs(Room.m_pChairs) do
		if seat.Player then
			Room.OnPlayerQuit(seat)
		end
	end
	Room.Close()
end

function Room.IsAllUserReady()
	local playcount,readycount = 0,0
	for _,seat in pairs(Room.m_pChairs) do
        if seat.m_isValid == 1 then
		  playcount = playcount + 1
        end

		if seat.IsReady == 1 then
			readycount = readycount+1
		end
	end
	return readycount >= playcount
end

function Room.GetSeatByPlayer(player)
	for _,seat in pairs(Room.m_pChairs) do
		if seat.Player and seat.Player.nPlayerId == player.nPlayerId then
			return seat
		end
	end
	return nil
end

function Room.SendMsgToAll(msg,seatId)
	for _,seat in pairs(Room.m_pChairs) do
		if seat.Player and seat.m_wChairId ~= seatId then
			Room.SendMsgToUser(seat,msg)
		end
	end
end

function Room.SendMsgToUser(seat,msg)
	if seat.Player then
		Send_Data(seat.Player.nAgentAddr,"send_data",msg)
	end
end

function Room.GetGameStatus()
	return Room.m_nGameState
end

function Room.SetGameStatus(status)
	Room.m_nGameState = status
end

function Room.GetRoomOwerId()
    return Room.m_dwOwnerPlayerId
end

function Room.GetRoomSeats()
    return Room.m_pChairs
end

function Room.OnNetMsgStandUpReq(Player) --用户离开桌子
    local seat = Room.GetSeatByPlayer(Player)

    skynet.error("[manager] OnNetMsgStandUpReq",seat.m_wChairId, seat.Player.nPlayerId, Room.nRoomId)
    if  not seat or not seat.Player then 
        return 
    end
    
    if Room.m_nGameState ~= Room.GAME_STATUS_WAIT and Room.m_nGameState ~= Room.GAME_STATUS_WAITNEXT then 
        skynet.error("[manager] OnNetMsgStandUpReq gamestart ...")
        --游戏已经开始，让玩家断线处理
        Room.OnUserNetCut(Player)
    else
        skynet.error("[manager] OnNetMsgStandUpReq not  gamestart ...")
        Room.m_n1MinCheckTick = 0
        Room.m_nGameState = Room.GAME_STATUS_WAIT

        Room.OnPlayerQuit(seat)
        Room.ClearUserInfo(seat)

        for _, seat in pairs(Room.m_pChairs) do 
            if seat.Player then 
                return 
            end
        end

        Room.Close()
    end
end

--清空玩身上的房间数据
function Room.ClearUserInfo(seat)
    seat.Player.nScore = 0
    seat.Player.nRoomId = 0   --更新用户数据
    seat.Player.nRoomAddr = 0
    seat.Player.nScore = 0

    Room.NotifyCenterServerTableStatus(TABLESTATUS_READY_OUT,math.floor(seat.Player.nPlayerId))

    if Room.GetPlayerCount() == Room.m_nPlayerCount then
        skynet.send(manager,"lua","TableIdle",Room.m_nRoomId)
    end

    seat:stand()
end

--玩家退出
function Room.OnPlayerQuit(seat)
    local msg = string.pack(">I2>I2<I2", 303, 2003, seat.m_wChairId)
    skynet.error("seat.m_wChairId = ",seat.m_wChairId)  
    Room.SendMsgToAll(msg)  
end

--玩家申请解散
function Room.OnNetMsgUserWantJieSanReq(seat)
    skynet.error("[manager] OnNetMsgUserWantJieSanReq ")
    
    if Room.m_nJieSanApplyerChairId then --已经在解散中略过
        return
    end

    if Room.m_bIsStarted == 1 then 
        Room.m_nJieSanApplyerChairId = seat.m_wChairId
        seat.m_nJieSanChoice = 2
        Room.m_nJieSanTimePoint = os.time()
        Room.SendJieSanData()
        Room.m_nDismissId = math.floor((Room.m_nDismissId + 1)%65535)
        skynet.fork(Room.OnTimer5MinJieSan)
        skynet.error("[manager]",Room.m_nRoomId," 用户: ",seat.Player.nPlayerId," 申请解散房间")
    else
        if seat.Player.nPlayerId == Room.m_dwOwnerPlayerId then --房主
            skynet.error("[manager]",Room.m_nRoomId," 用户: ",seat.Player.nPlayerId," 申请解散房间，其为房主，房间立即解散")
            Room.Dismiss()            
        end  
        
    end
end

--申请解散定时器，超过五分钟玩家没有响应自动解散
function Room.OnTimer5MinJieSan()
    local nDismissId = Room.m_nDismissId
    skynet.sleep(6000*5)
    if Room.m_nJieSanApplyerChairId and nDismissId == Room.m_nDismissId then
        Room.Dismiss()
    end
end

function Room.SendJieSanData(seat)
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(303,2023)
    BuffWrite:int2(Room.m_nJieSanApplyerChairId)
    BuffWrite:int4(Room.m_nPlayerCount)    
    for i=0, Room.m_nPlayerCount-1 do
            BuffWrite:int4(Room.m_pChairs[i].m_nJieSanChoice)       
    end     
    for _,seat in pairs(Room.m_pChairs) do
        BuffWrite:int4(0)
    end  
    
    local tt = Room.m_nJieSanTimePoint + 300 - os.time()
    BuffWrite:int4(tt)
    if seat then
        Room.SendMsgToUser(seat,BuffWrite.buff)
    else
        Room.SendMsgToAll(BuffWrite.buff)
    end
end

function Room.OnNetMsgUserDoChoice(smsg, Player)
    local seat = Room.GetSeatByPlayer(Player)
    if seat.playCount == 0 then
        return 
    end

    local BuffRead = buffread.new(smsg)
    BuffRead:proto()
    local nChoice   = BuffRead:int4()
    seat.m_nJieSanChoice = nChoice
    Room.SendJieSanData()
    local agree = 0
    local disagree = 0
    for _,seat in pairs(Room.m_pChairs) do
        if seat.Player then 
            if seat.m_nJieSanChoice == 2 then 
                agree = agree + 1
            elseif seat.m_nJieSanChoice == 1 then 
                disagree = disagree + 1
            end
        end
    end
    skynet.error("[manager] OnNetMsgUserDoChoice",nChoice,agree,disagree,Room.m_nPlayerCount/2)
    if agree > (Room.m_nPlayerCount/2) and agree ~= 1 then 
        Room.SendJieSanData()
        skynet.error("不写战绩 解散桌子")
        Room.Dismiss()
    else 
        if disagree >= Room.m_nPlayerCount/2  and disagree ~= 1 then
            for _, seat in pairs(Room.m_pChairs) do
                if seat.Player then                    
                    seat.m_nJieSanChoice = 0
                end
            end
            Room.m_nJieSanApplyerChairId = nil
        end   
    end                      
end

--写总结算战绩
function Room.WriteZhanJiDb()
    local ZhanJiTmp = {nPlayerId = nil,nGameId=Room.m_nGameId, 
    nTableId = Room.m_nRoomId,wMyChairId = nil, nGameRound = Room.m_wCurJu-1,
    nTotalRound = Room.m_wTotalJu,szTime = "",nPlayerIds={}, szNames = {}, nScores = {}}
    ZhanJiTmp.szTime= tostring(os.date("%Y-%m-%d %H:%M:%S",os.time()))
    for j=0,MaxPlayerCount-1 do
        if Room.m_pChairs[j] and Room.m_pChairs[j].Player then
            table.insert(ZhanJiTmp.nPlayerIds,math.floor(Room.m_pChairs[j].Player.nPlayerId))
            table.insert(ZhanJiTmp.szNames, Room.m_pChairs[j].Player.szName)
            table.insert(ZhanJiTmp.nScores, math.floor(Room.m_pChairs[j].Player.nScore))
        else
            table.insert(ZhanJiTmp.nPlayerIds,0)
            table.insert(ZhanJiTmp.szNames, "")
            table.insert(ZhanJiTmp.nScores, 0)
        end
    end
    for i=0,MaxPlayerCount-1 do 
        if Room.m_pChairs[i] and Room.m_pChairs[i].Player then
            ZhanJiTmp.wMyChairId = Room.m_pChairs[i].m_wChairId 
            ZhanJiTmp.nPlayerId = math.floor(Room.m_pChairs[i].Player.nPlayerId)
            lobbysql.WriteZhanJiDb(ZhanJiTmp)
        end
    end

    if Room.m_nGroupId > 0 then
        ZhanJiTmp.nGroupID = Room.m_nGroupId
        ZhanJiTmp.nCost = Room.m_nNeedFangKa
        ZhanJiTmp.nCreateID = Room.m_dwOwnerPlayerId
        ZhanJiTmp.szTime=tostring(os.date("%Y-%m-%d %H:%M:%S",math.ceil(Room.m_tCreateTime)))
        lobbysql.SpcWriteGameScore(ZhanJiTmp)
    end
end

function Room.OnGameMessage(scmd,smsg,Player)
    skynet.error("[tableframe]",scmd)
    --TableFrameSink:OnGameMsg(scmd, smsg, Player)
    local seat = Room.GetSeatByPlayer(Player)
    if seat then
        Room.ResetWorkCount()
        gameLogic:OnGameMsg(scmd,smsg,Player)
    end
end


function Room.AgentDismissRoom(nAgentID)
    if not Room.m_nAgentID or Room.m_nAgentID ~= nAgentID then
        return
    end
    --房间已开始返回掉
    if Room.m_bIsStarted ~= 0 then
        return
    end
    Room.SendMsgToAll(Room.PackCenterHintMsg("代理解散了房间"))
    Room.Dismiss()
end

--更新中心服信息
function Room.NotifyCenterServerTableStatus(nStatus,nPlayerID)
    if nPlayerID then
        local nps = string.pack("I4I1I1I4",math.floor(Room.m_nRoomId),nStatus,1,math.floor(nPlayerID))
        SendToCenter(CEN.Main_Center_module,CEN.Sub_ModuleToCenter_UpdateTable,nps)
        return
    end

    local BuffWrite = buffwrite.new() 
    BuffWrite:Int4(Room.m_nRoomId)
    BuffWrite:int1(nStatus)

    local playerIds = {}
    local nCount = 0
    for i=0,Room.m_nPlayerCount-1 do
        if Room.m_pChairs[i].Player then
            nCount = nCount + 1
            table.insert(playerIds,math.floor(Room.m_pChairs[i].Player.nPlayerId))
        end
    end

    BuffWrite:int1(nCount)
    for _,v in pairs(playerIds) do
        BuffWrite:Int4(v)
    end
    SendToCenter(CEN.Main_Center_module,CEN.Sub_ModuleToCenter_UpdateTable,BuffWrite.buff)
end
--游戏桌状态变更更新到中心服
function Room.AgentGameChg(nStatus)
    if Room.m_nAgentID == 0 then
        return
    end

    local ds = {nPlayerID = Room.m_nAgentID,nTableID = Room.m_nRoomId,nStatus = nStatus}
    local res = lobbysql.OnAgentTableStatus(ds)
    if res and nStatus == AGENT_TBL_DISMISS then
        local msg = string.pack("ii",Room.m_nAgentID,Room.m_nRoomId)
        SendToCenter(CMD.Main_Hall_CMD,CMD.Sub_NotifyTableDismiss,msg)
    end
end

--10分钟无操作解散桌子定时器,每秒检测
function Room.OnTimerCheckWork()
    while true do
        skynet.sleep(100)
        Room.m_nTimerWorkCount = Room.m_nTimerWorkCount + 1
        if Room.m_nTimerWorkCount >= 10*60 then
            Room.SendMsgToAll(Room.PackCenterHintMsg("由于房间十分钟内无有效操作，房间解散"))
            if Room.m_wCurJu == 1 then
                Room.Dismiss()
            else
                Room.Close()
            end
            skynet.error("桌子超过10分钟无有效操作，桌子被解散.")
        end
    end
end

function Room.ResetWorkCount()
    Room.m_nTimerWorkCount = 0
end
--发送聊天信息
function Room.OnNetMsgUserWantVoiceReq(smsg,player)
    local which = string.unpack("I4",smsg,5)
    local seat = Room.GetSeatByPlayer(player)
    local msg = string.pack(">I2I2<I2I4",CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_UserWantVoiceResult,
        seat.m_wChairId,which or 0)
    Room.SendMsgToAll(msg)
end
--发送表情
function Room.OnNetMsgUserWantFaceReq(smsg,player)
    local which = string.unpack("I4",smsg,5)
    local seat = Room.GetSeatByPlayer(player)
    local msg = string.pack(">I2I2<I2I4",CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_UserWantFaceResult,
        seat.m_wChairId,which or 0)
    Room.SendMsgToAll(msg)
end
--道具请求
function Room.OnNetMsgUserPropReq(smsg,player)
    local wFromChair,wToChair,nPropID = string.unpack("I2I2i",smsg,5)

    local seat = Room.GetSeatByPlayer(player)
    if wFromChair ~= seat.m_wChairId then
        return
    end

    if not Prop[nPropID] then
        return
    end

    if player.llJinBi < Prop[nPropID].price then
        return
    end

    if lobbysql.AddOrSubPlayerJinBi(player,-Prop[nPropID].price,"使用道具") then
            lobbysql.UpdatePlayerBasicInfo(player)

    else
        return
    end

   local msg = string.pack(">I2I2<I2I2i",
    CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_PropResp,
    wFromChair,wToChair,nPropID
    )
   Room.SendMsgToAll(msg)
end

function Room.OnNetMsgUserSendTxtReqs(smsg,player)
    local nPlayerId,szMsg = string.unpack("ic256",smsg,5)
    szMsg = filter:maskString(szMsg)
    local msg = string.pack(">I2>I2<ic256",CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_SendTxt,
        nPlayerId,szMsg)
    Room.SendMsgToAll(msg)
end

function Room.UpdateAllPlayerJinBiToClient()
    local BuffWrite = buffwrite.new()
    BuffWrite:clean()
    BuffWrite:proto(CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_UpdateAllPlayerJinBi)
    BuffWrite:Int4(Room.m_nPlayerCount)
    for i=0,MaxPlayerCount-1 do
        local seat = Room.m_pChairs[i]
        if seat and seat.Player then
            BuffWrite:int8(seat.Player.llJinBi)
        else
            BuffWrite:int8(0)
        end
    end
    Room.SendMsgToAll(BuffWrite.buff)
end

function Room.OnUserNetCut(player)
    if Room.m_nGameState == Room.GAME_STATUS_WAIT or Room.m_nGameState == Room.GAME_STATUS_WAITNEXT then
        Room.OnNetMsgStandUpReq(player)
        return
    end 

    local seat = Room.GetSeatByPlayer(player)
    if seat then
        Room.UpdatePlayerOnLineInfo(seat,1)
        gameLogic:UserNetCut(seat)
    end
end

function Room.UpdatePlayerOnLineInfo(seat,status)
    if seat and seat.m_isValid == 1 then

        if status == 1 then
            seat.IsOffLine = true
        else
            seat.IsOffLine = false
        end

       local msg = string.pack(">I2>I2<I2I1",
       CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_UpdateDisconnectState,
       seat.m_wChairId,status) 
       Room.SendMsgToAll(msg)
    end
end

function Room.PackCenterHintMsg(szMsg)
    local msg = string.pack(">I2>I2<c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,szMsg)
    return msg
end

function Room.SendCenterHintMsgBuyZuan(player,szMsg)
    local msg = string.pack(">I2>I2<c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsgBuyZuan,szMsg)
    Send_Data(player.nAgentAddr,"send_data",msg)
end
--GPS处理
function Room.OnNetMsgGPSData(smsg,player)
    local seat = Room.GetSeatByPlayer(player)
    if not seat then return end
    local gps_x,gps_y = string.unpack("ff",smsg,5)
    seat.GPS_X = gps_x
    seat.GPS_Y = gps_y
    --Room.SendMyPlayerInfoToOther(seat)
    local msg = string.pack(">I2>I2<iff",CMDGAME.Main_ClientAndGameSvr_TableModle,CMDGAME.Sub_GameSvrToClient_TableModle_GPS,
        math.floor(player.nPlayerId),gps_x,gps_y)
    Room.SendMsgToAll(msg)
end

skynet.start(function()
    skynet.error("tableframe server start...")
	skynet.dispatch("lua", function(_,_, command, ...)
		local f = Room[command]
        if f then
		  skynet.ret(skynet.pack(f(...)))
        end
	end)
    math.randomseed(os.time())
end)